#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <float.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/time.h>
#include <time.h>

#include "public.h"
#include "debug.h"

/*
 * abstruct : get GPS time.
 *
 * example:
 * #MARKTIMEA,COM1,0,41.0,FINESTEERING,1975,457422.959,00000000,292e,14392;1975,457422.958801440,7.184707455e-08,1.391773761e-09,-18.000000000,VALID*4f9858ff
 */

#define YEAR_TURN_SECOND(year)	(((year) * 365 * 24 * 60 * 60 + 2 * 24 * 60 * 60) - 1) /* 315532800, 1970~1980 */ 
#define WEEK_TRUN_SECOND(week)	((week) * 7 * 24 * 60 * 60 )

#ifdef VERIFICATION
static int set_time_flag = 1;
#endif

static int get_time_value(char * pdata);
static int set_time_prepare(long week, double seconds, double offset, double offset_std, double utc_offset);
static int set_system_time(long tv_sec, long tv_usec);

int time_analysis(char * pdata)
{
	char * p;
	char buf[256];
	const char * delim = ";";

	trace_dbg(DEBUG_MSG_LEVEL_VERBOSE, "pdata;%s\n", pdata);

	p = strtok(pdata, delim);

	while (p != NULL) {
		trace_dbg(DEBUG_MSG_LEVEL_VERBOSE, "%s\n", p);

		memset(buf, 0, sizeof buf);
		strcpy(buf, p);
		p = strtok(NULL, delim);
	}

	trace_dbg(DEBUG_MSG_LEVEL_VERBOSE, "b:%s\n", buf);

	get_time_value(buf);

	return 0;
}

static int get_time_value(char * pdata)
{
	long week = 0.0;
	double seconds = 0.0;
	double offset = 0.0;
	double offset_std = 0.0;
	double utc_offset = 0.0;
	char status[12] = "0";
	char flag[8] = "0";
	
	sscanf(pdata, "%ld,%lf,%le,%le,%lf,%s", &week, &seconds, &offset, &offset_std, &utc_offset, status);

	trace_dbg(DEBUG_MSG_LEVEL_VERBOSE, "%ld, %lf, %le, %le, %lf, %s\n", week, seconds, offset, offset_std, utc_offset, status);

	strncpy(flag, status, 5);	/* get status value */

	/* campare status value */
	if (!strcmp(flag, "VALID")) {
		set_time_prepare(week, seconds, offset, offset_std, utc_offset);
	}
	else {
		trace_dbg(DEBUG_MSG_LEVEL_ERROR, "%s:this time status is invalid.\n", __FUNCTION__);
	}

	return 0;
}

static int set_time_prepare(long week, double seconds, double offset, double offset_std, double utc_offset)
{
	long tv_sec;
	long tv_usec;
	double fractpart, intpart;

	trace_dbg(DEBUG_MSG_LEVEL_VERBOSE, "%ld, %lf, %le, %le, %lf\n", week, seconds, offset, offset_std, utc_offset);

	tv_sec = (long)YEAR_TURN_SECOND(10) + (long)WEEK_TRUN_SECOND(week) + (long)seconds;
	// tv_sec += 28800; /* UTC + 8 */

	/* deviation value */
	tv_sec += (5 * 24 * 3600);	
	trace_dbg(DEBUG_MSG_LEVEL_INFO, "s:%ld\n", tv_sec);
	
	fractpart = modf(seconds, &intpart);
	trace_dbg(DEBUG_MSG_LEVEL_INFO, "ss %lf %lf\n", intpart, fractpart);

	tv_usec = fractpart * 1000000;
	trace_dbg(DEBUG_MSG_LEVEL_INFO, "u:%ld\n", tv_usec);

	#ifndef VERIFICATION
	set_system_time(tv_sec, tv_usec);
	#else
	/* display_gps_time(tv_sec); */
	display_gps_microsecond(tv_sec, tv_usec);

	if (set_time_flag) {
		set_system_time(tv_sec, tv_usec);
	}
	#endif
	
	return 0;
}

static int set_system_time(long tv_sec, long tv_usec)
{
	int ret;
	struct timeval time_tv;

	time_tv.tv_sec = tv_sec;
	time_tv.tv_usec = tv_usec;

	putenv("TZ=UTC-8");
	putenv("TZ=CST-8"); // china
	tzset();

	#ifdef DUBUG
	printf( "daylight = %d\n", daylight ); 
	printf( "timezone = %ld\n", timezone ); 
	printf( "tzname[0] = %s\n", tzname[0] );
	#endif

	ret = settimeofday(&time_tv, NULL);
	if (ret != 0) {
		trace_dbg(DEBUG_MSG_LEVEL_ERROR, "settimeofday failed.\n");
		return -1;
	}
	else {
		#ifdef VERIFICATION
		set_time_flag = 0;
		trace_dbg(DEBUG_MSG_LEVEL_INFO, " settimeofday success! \n");
		#endif		
	}

	return 0;
}



